﻿using IWshRuntimeLibrary;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Foundation;
using Windows.Management.Deployment;
using Log = Logger.Debug;

namespace Xiaowei.Services
{
    
    public interface IOpenAppService
    {
        void Init();
        IEnumerable<string> AppList
        {
            get;
            
        }
        bool OpenApp(string appName);
        ManualResetEvent InitWaiter 
        {
            get;
        }
    }

    internal static class OpenAppServiceWin32
    {
        static OpenAppServiceWin32()
        {
            RequeryApps();
        }
        public static IReadOnlyList<string> AppList { 
            get
            {
                return AppNamePathMap.Keys.ToList();
            } 
        }
        private static Dictionary<string, string> AppNamePathMap = new Dictionary<string, string>();
        static bool queryOK=false;
        public static ManualResetEvent InitWaiter { get; } = new ManualResetEvent(false);
        private static void RequeryApps()
        {
            InitWaiter.Reset();
            AppNamePathMap.Clear();
            Queue<string> paths = new Queue<string>();
            paths.Enqueue(@"C:\ProgramData\Microsoft\Windows\Start Menu");
            paths.Enqueue(Environment.GetFolderPath(System.Environment.SpecialFolder.StartMenu));
            while (paths.Count != 0)
            {
                string path = paths.Dequeue();
                string[] items = null;

                try
                {
                    items = Directory.GetFiles(path);
                }
                catch (Exception ex)
                {
                    Log.WriteLine(ex);
                    continue;
                }
                foreach (var item in items)
                {
                    //Log.WriteLine($"item:{item}");
                    if (item.ToLower().EndsWith(".lnk"))
                    {
                        WshShell shell = new WshShell();
                        IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(item);
                        string realPath = shortcut.TargetPath;
                        if (!realPath.ToLower().EndsWith(".exe"))
                        {
                            continue;
                        }

                        string name = Path.GetFileNameWithoutExtension(item).ToUpper();

                        if (!AppNamePathMap.ContainsKey(name))
                        {
                            //Log.WriteLine($"name:{name}, item:{item}");
                            AppNamePathMap.Add(name, item);
                        }
                    }
                }
                foreach (var item in Directory.GetDirectories(path))
                {
                    paths.Enqueue(item);
                }
            }
            InitWaiter.Set();
        }
        public static bool OpenApp(string appName)
        {
            if (!queryOK)
            {
                return false;
            }
            if (!AppNamePathMap.ContainsKey(appName))
            {
                return false;
            }
            try
            {
                Process.Start(AppNamePathMap[appName]);
            }
            catch (Exception ex)
            {
                Log.WriteLine(ex.ToString());
                return false;
            }
            return true;
        }
    }

    









    public interface IAppRun
    {
        bool RunApp();
        string AppName { get; set; }
    }

    public class AppRun : IAppRun
    {
        public string AppName
        {
            get; set;
        }

        private AppListEntry appListEntry;

        public void SetEntry(AppListEntry entry)
        {
            this.appListEntry = entry;
        }

        public bool RunApp()
        {
            IAsyncOperation<bool> result = null;
            result = appListEntry?.LaunchAsync();
            return Task.Run(async () => { return await result; }).Result;
        }
    }

    public class Win32AppRun : IAppRun
    {
        public string AppName
        {
            get; set;
        }

        public bool RunApp()
        {
            return OpenAppServiceWin32.OpenApp(AppName);
        }
    }

    public class OpenAppService : IOpenAppService
    {
        public event EventHandler AppInitEndEvent;
        public bool IsGetAppListEnd { get; set; } = false;
        public IEnumerable<string> AppList => AppMap.Keys;
        public bool OpenApp(string appName)
        {
            string app = appName.ToUpper();
            if (!AppMap.ContainsKey(app))
            {
                return false;
            }
            else
            {
                return AppMap[app].RunApp();
            }
        }
        public ManualResetEvent InitWaiter { get; } = new ManualResetEvent(false);
        public OpenAppService()
        {
        }
        private bool isInited = false;
        public void Init()
        {
            if (isInited)
            {
                return;
            }
            isInited = true;
            GetAppTask();
        }

        Dictionary<string, IAppRun> AppMap = new Dictionary<string, IAppRun>();

        public async void GetAppTask()
        {
            if (IsGetAppListEnd) return;
            Logger.Debug.WriteLine("GetAppTask() start");
            AppMap.Clear();
            PackageManager packageManager = new PackageManager();
            IEnumerable<Windows.ApplicationModel.Package> packages = packageManager.FindPackagesForUser("");
            foreach (var obj in packages)
            {
                var t = (await obj.GetAppListEntriesAsync());
                foreach (var item in t)
                {
                    AppRun appRun = new AppRun();
                    appRun.AppName = item.DisplayInfo.DisplayName.ToUpper();
                    appRun.SetEntry(item);
                    if (AppMap.ContainsKey(appRun.AppName)) continue;
                    AppMap.Add(appRun.AppName, appRun);
                }
            }
            foreach (var item in OpenAppServiceWin32.AppList)
            {
                Win32AppRun win32AppRun = new Win32AppRun() { AppName = item };
                if (AppMap.ContainsKey(win32AppRun.AppName)) continue;
                AppMap.Add(win32AppRun.AppName, win32AppRun);
            }
            AppInitEndEvent?.Invoke(this, EventArgs.Empty);
            IsGetAppListEnd = true;
            InitWaiter.Set();
            Logger.Debug.WriteLine("GetAppTask() end");
        }
    }
}
